#include "plugin.h"

#include <string.h>

// ----------------------------------------------------------------------------
// --- global GUI -------------------------------------------------------------
// ----------------------------------------------------------------------------

enum { ID_PART_ONLY = 0x8001, ID_WRITE_TRACE };

static LWXPanelControl bwPanelControlList[] = {
    { ID_PART_ONLY,   "Render particles only",                "iBoolean" },    
    { ID_WRITE_TRACE, "Write Debug Log",                      "iBoolean" },
    { 0 }
};

static LWXPanelDataDesc bwPanelDataDescList[] = {
    { ID_PART_ONLY,   "Render particles only",                "integer" },
    { ID_WRITE_TRACE, "Write Debug Log ",                     "integer" },
    { 0 }
};

static LWXPanelHint bwPanelHintList[] = {
    XpLABEL(0, "Global Settings" ),
    XpEND
};

void* BWPanelData_get (void *inst, unsigned long controlID)
{
    BWInstanceData* instance = (BWInstanceData*) inst;
    void* result = NULL;
    static int intVal;
    static double doubleVal;
            
    // returning pointers to the static elements was done like this in a
    // sample. TODO: check if I can return the addresses directly

    if (instance)
    {
        switch (controlID)
        {
        case ID_PART_ONLY: 
            intVal = instance->renderParticlesOnly;
            result = &intVal;
            break;
        case ID_WRITE_TRACE:
            intVal = instance->writeTrace;
            result = &intVal;
            break;
        }
    }

    return result;  
}

// ----------------------------------------------------------------------------
LWXPRefreshCode BWPanelData_set (void *inst, unsigned long controlID, 
                                 void *value)
{
    int retVal = LWXPRC_NONE;
    
    BWInstanceData* instance = (BWInstanceData*) inst;

    if (instance)
    {
        switch (controlID)
        {
        case ID_PART_ONLY:
            instance->renderParticlesOnly = *((int*)value);
            retVal = LWXPRC_DFLT;
            break;
        case ID_WRITE_TRACE:
            instance->writeTrace = *((int*)value);
            retVal = LWXPRC_DFLT;
            break;
        }
    }
   
    EnableTrace(instance->writeTrace);

    return retVal;
}

// ----------------------------------------------------------------------------
LWXPanelID BWCreatePanel(BWInstanceData* instance)
{
    const LWXPanelFuncs* panelFuncs = NULL;
    GlobalFunc* global = instance->globalFunc;
    
    LWXPanelID panelID = NULL;

    panelFuncs = getLWPanelFuncs(global);
    
    if (panelFuncs)
    {
        panelID = panelFuncs->create(LWXP_VIEW, bwPanelControlList);
        if (panelID)
        {
            panelFuncs->hint(panelID, 0, bwPanelHintList);
            panelFuncs->describe(panelID, bwPanelDataDescList,
                                 BWPanelData_get, BWPanelData_set);
            panelFuncs->viewInst(panelID, instance);
            panelFuncs->setData(panelID, 0, instance);
        }
    }
    
    return panelID;
}

// ----------------------------------------------------------------------------
// --- custom object GUI ------------------------------------------------------
// ----------------------------------------------------------------------------

enum { ID_SIZE = 0x8001, ID_DENSITY, ID_COLVAR, ID_COLDISP, 
       ID_BRUSHFILE, ID_ALIGN, ID_BFCULL };

static LWXPanelControl bwCoPanelControlList[] = {
    { ID_BRUSHFILE, "Brush Image",                 "sFileName" },
    { ID_SIZE,      "Particle Size",               "float" },
    { ID_DENSITY,   "Particle Density",            "float" },
    { ID_COLVAR,    "Colour Variance",             "percent" },
    { ID_COLDISP,   "Colour Displacement",         "float" },
    { ID_ALIGN,     "Particle Alignment",          "iBoolean" },
    { ID_BFCULL,    "Backface Culling",            "iBoolean" },
    { 0 }
};

static LWXPanelDataDesc bwCoPanelDataDescList[] = {
    { ID_BRUSHFILE, "Brush Image",                 "string" },
    { ID_SIZE,      "Particle Size",               "float" },
    { ID_DENSITY,   "Particle Density",            "float" },
    { ID_COLVAR,    "Colour Variance",             "percent" },
    { ID_COLDISP,   "Colour Displacement",         "float" },
    { ID_ALIGN,     "Particle Alignment",          "integer" },
    { ID_BFCULL,    "Backface Culling",            "integer" },
    { 0 }
};

static LWXPanelHint bwCoPanelHintList[] = {
    XpLABEL(0, "Particle Settings" ),
    XpMIN(ID_SIZE, 0),
    XpMAX(ID_SIZE, 1),
    XpMIN(ID_COLVAR, 0),
    XpMAX(ID_COLVAR, 1),
    XpXREQCFG(ID_BRUSHFILE, LWXPREQ_LOAD, "Select brush file", LWFTYPE_IMAGE ),
    XpDIVADD(ID_BRUSHFILE),
    XpEND
};

// ----------------------------------------------------------------------------
void* BWcoPanelData_get (void *inst, unsigned long controlID)
{
    BWcoInstanceData* instance = (BWcoInstanceData*) inst;
    void* result = NULL;
    static int intVal;
    static double doubleVal;
    static char stringVal[MAX_FILENAME_LENGTH];
    RenderSettings* options = &instance->renderSettings;
    
    // returning pointers to the static elements was done like this in a
    // sample. TODO: check if I can return the addresses directly

    if (instance)
    {
        switch (controlID)
        {
        case ID_SIZE: 
            doubleVal = options->partSize;
            result = &doubleVal;
            break;
        case ID_DENSITY:
            doubleVal = options->partDensity;
            result = &doubleVal;
            break;
        case ID_COLVAR:
            doubleVal = options->colorVariation;
            result = &doubleVal;
            break;
        case ID_COLDISP:
            doubleVal = options->colorDisplacement;
            result = &doubleVal;
            break;
        case ID_BRUSHFILE:
            strcpy_s(stringVal, MAX_FILENAME_LENGTH, options->brushFilename);
            result = stringVal;
            break;
        case ID_ALIGN:
            intVal = options->alignParticles;
            result = &intVal;
            break;
        case ID_BFCULL:
            intVal = options->backFaceCulling;
            result = &intVal;
            break;
        }
    }

    return result;  
}

// ----------------------------------------------------------------------------
LWXPRefreshCode BWcoPanelData_set (void *inst, unsigned long controlID, 
                                   void *value)
{
    int retVal = LWXPRC_NONE;
    
    BWcoInstanceData* instance = (BWcoInstanceData*) inst;
    RenderSettings* options = &instance->renderSettings;

    if (instance)
    {
        switch (controlID)
        {
        case ID_SIZE:
            options->partSize = (float) *((double*)value);
            retVal = LWXPRC_DFLT;
            break;
        case ID_DENSITY:
            options->partDensity = (float) *((double*)value);
            retVal = LWXPRC_DFLT;
            break;
        case ID_COLVAR:
            options->colorVariation = (float) *((double*)value);
            retVal = LWXPRC_DFLT;
            break;
        case ID_COLDISP:
            options->colorDisplacement = (float) *((double*)value);
            retVal = LWXPRC_DFLT;
            break;
        case ID_BRUSHFILE:
            {
                const char* contentDir = getLWDirectory(instance->globalFunc, 
                    LWFTYPE_CONTENT);
                strncpy_s(options->brushFilename, MAX_FILENAME_LENGTH, 
                    (const char*)value, MAX_FILENAME_LENGTH); 
                // remove content dir, if it is found in string
                strReplace(options->brushFilename, MAX_FILENAME_LENGTH,
                    contentDir, "");           
            }
            retVal = LWXPRC_DFLT;
            break;
        case ID_ALIGN:
            options->alignParticles = *((int*)value);
            retVal = LWXPRC_DFLT;
            break;
        case ID_BFCULL:
            options->backFaceCulling = *((int*)value);
            retVal = LWXPRC_DFLT;
            break;
        }
    }

    // replace invalid values
    if (options->partSize <= 0) options->partSize = 0.01f;
    if (options->partDensity < 0) options->partDensity = 0;
    if (options->partDensity > 1000) options->partDensity = 1000;
    if (options->colorVariation < 0) options->colorVariation = 0;
    if (options->colorVariation > 1) options->colorVariation = 1;
    if (strlen(options->brushFilename) == 0)
        strcpy_s(options->brushFilename, MAX_FILENAME_LENGTH, DEFAULT_BRUSH);

    return retVal;
}

// ----------------------------------------------------------------------------
LWXPanelID BWcoCreatePanel(BWcoInstanceData* instance)
{
    const LWXPanelFuncs* panelFuncs = NULL;
    GlobalFunc* global = instance->globalFunc;
    
    LWXPanelID panelID = NULL;

    panelFuncs = getLWPanelFuncs(global);
    
    if (panelFuncs)
    {
        panelID = panelFuncs->create(LWXP_VIEW, bwCoPanelControlList);
        if (panelID)
        {
            panelFuncs->hint(panelID, 0, bwCoPanelHintList);
            panelFuncs->describe(panelID, bwCoPanelDataDescList,
                                 BWcoPanelData_get, BWcoPanelData_set);
            panelFuncs->viewInst(panelID, instance);
            panelFuncs->setData(panelID, 0, instance);
        }
    }
    
    return panelID;
}
